package com.auditlog.boot.aop.datasource;

import com.auditlog.datasource.ConnectionProxy;
import com.auditlog.datasource.DataSourceProxy;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

import javax.sql.DataSource;
import java.lang.reflect.Method;

/**
 * @author Zhiyang.Zhang
 * @version 1.0
 * @date 2022/12/4 11:29
 */
public class AuditLogDataSourceInterceptor implements MethodInterceptor {
    private static final String PROXY_METHOD_NAME = "getConnection";

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Method method = invocation.getMethod();
        String name = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        Method declared;
        try {
            declared = DataSource.class.getDeclaredMethod(name, parameterTypes);
        } catch (NoSuchMethodException e) {
            // 调用的方法不是datasource中定义的
            return invocation.proceed();
        }
        DataSource origin = (DataSource) invocation.getThis();
        DataSourceProxy proxy = DataSourceProxyHolder.get(origin);
        Object[] args = invocation.getArguments();
        Object result = declared.invoke(proxy, args);
        if (name.equals(PROXY_METHOD_NAME)) {
            if (result instanceof ConnectionProxy) {
                ProxyFactory proxyFactory = new ProxyFactory(result);
                proxyFactory.addAdvice(new ConnectionMethodInterceptor((ConnectionProxy) result));
                return proxyFactory.getProxy();
            }
        }
        return result;
    }
}
